package com.dark.quick;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.concurrent.CountDownLatch;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 负责文件下载的类
 */
public class DownloadThreadTask implements Runnable {

	private static final Logger LOGGER = LoggerFactory.getLogger(DownloadThreadTask.class);
    /**
     * 待下载的文件
     */
    private String url = null;

    /**
     * 本地文件名
     */
    private String fileName = null;

    /**
     * 偏移量
     */
    private long offset = 0;

    /**
     * 分配给本线程的下载字节数
     */
    private long length = 0;
    
    private CountDownLatch end;
    private CloseableHttpClient httpClient;
    private HttpContext context;
    private int count = 0;

    /**
     * @param url
     *            下载文件地址
     * @param fileName
     *            另存文件名
     * @param offset
     *            本线程下载偏移量
     * @param length
     *            本线程下载长度
     */
    public DownloadThreadTask(String url, String file, long offset, long length, CountDownLatch end, CloseableHttpClient httpClient) {
        this.url = url;
        this.fileName = file;
        this.offset = offset;
        this.length = length;
        this.end = end;
        this.httpClient = httpClient;
        this.context = new BasicHttpContext();
        System.out.println("偏移量=" + offset + ";字节数=" + length);
    }
    
	public void run() {
		excuce();
		end.countDown();
		// System.out.println(end.getCount() + " is go on!");
		LOGGER.info(end.getCount() + " is go on!");
	}

	private void excuce() {
		File newFile = new File(fileName);
		HttpGet httpGet = new HttpGet(this.url);
		httpGet.addHeader("Range", "bytes=" + this.offset + "-" + (this.offset + this.length - 1));
		httpGet.addHeader("Referer", "http://api.bilibili.com");
		RequestConfig requestConfig = RequestConfig.custom()
				.setConnectionRequestTimeout(-1)////从连接池中获取连接的超时时间 
				.setConnectTimeout(15*60*1000)//与服务器连接超时时间：httpclient会创建一个异步线程用以创建socket连接，此处设置该socket的连接超时时间  
				.setSocketTimeout(15*60*1000).//socket读数据超时时间：从服务器获取响应数据的超时时间  
				build();//设置请求和传输超时时间
		httpGet.setConfig(requestConfig);
		try (CloseableHttpResponse response = httpClient.execute(httpGet, context);
				BufferedInputStream bis = new BufferedInputStream(response.getEntity().getContent());
				RandomAccessFile raf = new RandomAccessFile(newFile, "rw");) {
			byte[] buff = new byte[1024];
			int bytesRead;
			while ((bytesRead = bis.read(buff, 0, buff.length)) != -1) {
				raf.seek(this.offset);
				raf.write(buff, 0, bytesRead);
				this.offset = this.offset + bytesRead;
			}
		} catch (ClientProtocolException e) {
			LOGGER.error("{} DownloadThread exception msg:{}", end.getCount(), ExceptionUtils.getFullStackTrace(e));
		} catch (IOException e) {
			LOGGER.error("{} DownloadThread exception msg:{}", end.getCount(), ExceptionUtils.getFullStackTrace(e));
			if (++count < 3) {
				LOGGER.error("====> {} RedownloadThread exception: {}", end.getCount(), count);
				run();
			} else {
				LOGGER.error("====> over {} RedownloadThread exception: {}", end.getCount(), count);
			}
		}
	}
}
